// const { includes, xor } = require("lodash")


// 1.默认三个状态
const PENDING = 'PENDING' // padidng
const FULFILLED = 'FULFILLED' // 成功
const REJECTED = 'REJECTED' // 失败


// 只考虑 new Promise多次.then时， 但是不能链式.then().then()
/*
class MyPromise {
    constructor(executor) { // 2.用户传入一个executor
        this.status = PENDING;
        // 这里可以用一个变量，为了看的清除 用2来表示
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = []; // 存放成功的回调的
        this.onRejectedCallbacks = []; // 存放失败的回调的

        const resolve = (value) => {
            if (this.status === PENDING) {
                this.status = FULFILLED
                this.value = value;
                // 异步的情况
                this.onResolvedCallbacks.forEach(fn=>fn());
            }
        }
        const reject = (reason) => {
            if (this.status === PENDING) {
                this.status = REJECTED
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn=>fn());
            }
        }
        try {
            executor(resolve, reject); // 3.这个代码执行的时候可能会发生异常
        } catch (e) {
            reject(e);
        }
    }
    then(onFulfilled, onRejected) { // 4.调用then的时候来判断成功还是失败
        // 执行成功和失败的逻辑
        if(this.status ===FULFILLED ){
            onFulfilled(this.value);
        }
        if(this.status === REJECTED){
            onRejected(this.reason)
        }
        // 异步的情况
        if(this.status === PENDING){
            this.onResolvedCallbacks.push(()=>{
                // 放自己的逻辑....
                onFulfilled(this.value);
            });
            this.onRejectedCallbacks.push(()=>{
                onRejected(this.reason);
            })
        }
    }
}
const my = new MyPromise((resolve,reject)=>{
    // resolve('ok')
    setTimeout(() => {
        resolve('ok2')
    })
})
my.then(res =>{
    console.log(res,3);
})
my.then(res =>{
    console.log(res,3);
})
*/



/*
开始考虑可以连续.then().then()的情况 但是在.then()中可能返回原始值，也可能是promise
要实现连续.then().then() .then中return 的必须是一个promsie 
核心是resolvePromise方法
    1.判断当前then中return的promise和调用的promise不是同一个
    2.判断当前x是不是一个promsie，判断方法 1：是一个对象||函数，2：有then方法
    3.判断y是不是一个promise，如果是递归调用，直到是原始值
*/
function resolvePromise(promise2, x, resolve, reject) {
    // 避免重复调用
    if (promise2 === x) {
        reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]'));
    }
    // 如何判断一个值是不是promise?  有没有then方法，有then方法的前提得是 x是一个对象或者函数
    // 为什么要这样判断，因为promise有可能不同的人实现方法不同，唯一能确定的就是 1：是一个对象||函数，2：有then方法
    if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
        let called = false;
        try {
            let then = x.then; 
            // 有then，是promise的情况
            if (typeof then === 'function') { 
                // 如果有一个then方法那么就说他是promise
                // 这里就是promise 要判断是成功的promise还是失败的promise
                // 这里直接用上次取出的then来继续使用，防止再次取then发生异常
                then.call(x, y => {
                    if (called) return
                    called = true;
                    // 判断y是不是一个promise，如果是递归调用，直到是原始值，
                    // 注意这里向下传递resolve、reject是调用者的promise状态
                    // 看下面的例子
                    resolvePromise(promise2, y, resolve, reject)
                }, r => {
                    if (called) return;
                    called = true;
                    reject(r);
                });
            } else {
                // 不是promise 普通值的情况
                resolve(x); 
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e); // 直接失败即可
        }
    } else {
        resolve(x); // 这里直接成功即可 普通值的情况
    }
}
class Promise {
    constructor(executor) {
        this.status = PENDING;
        // 这里可以用一个变量，为了看的清除 用2来表示
        this.value = undefined;
        this.reason = undefined;

        this.onResolvedCallbacks = []; // 存放成功的回调的
        this.onRejectedCallbacks = []; // 存放失败的回调的
        const resolve = (value) => {
            // 这里我们添加一个规范外的逻辑 让value值是promise的话可以进行一个解析
            // 处理Promise.resolve()静态方法resolve()中在放一个promise的情况
            if(value instanceof Promise){
                // 递归解析值，直到是原始值将其返回，
                // 传递的一直是最外层的resolve 和 reject，this永远是最外层的this,直到是原始值时执行下面的this代码
                console.log(this,123);
                return value.then(resolve,reject)
            }
            if (this.status === PENDING) {
                this.status = FULFILLED
                this.value = value;
                this.onResolvedCallbacks.forEach(fn => fn());
            }
        }
        const reject = (reason) => {
            if (this.status === PENDING) {
                this.status = REJECTED
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        }
        try {
            executor(resolve, reject); // 3.这个代码执行的时候可能会发生异常
        } catch (e) {
            reject(e);
        }
    }
    then(onFulfilled, onRejected) { // 4.调用then的时候来判断成功还是失败

        // 当then中没有传入函数时，添加默认
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

        let promise2 = new Promise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 用setTimeout是因为then中返回的promsie不能和当前的promise相同，会造成循环调用
               /* 
                    let promise2 = promise.then(() => {
                        retrun promise2
                    })
                    promise2要等return中的promise2执行成功。
                    但是两个promise2是相同的，这时候就出现了循环调用
               */
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value);
                        // 核心
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) { // 执行对应的回调时发生异常就执行promise2的失败
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) { // 执行对应的回调时发生异常就执行promise2的失败
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push(() => {
                    // 放自己的逻辑....
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) { // 执行对应的回调时发生异常就执行promise2的失败
                            reject(e);
                        }
                    }, 0)
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) { // 执行对应的回调时发生异常就执行promise2的失败
                            reject(e);
                        }
                    }, 0)
                })
            }
        });

        return promise2
    }

    catch(errorCallback){
        return this.then(null,errorCallback)
    }
}
// 静态方法
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason)
    })
}
Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        resolve(value)
    })
}

// all的并行 循环就是并发  所有都成功才是成功
Promise.all = function(promises){
    return new Promise((resolve,reject)=>{
        let arr = [];
        let times = 0;
        function processData(key,value){
            arr[key] = value;
            if(promises.length === ++times){
                resolve(arr)
            }
        }
        for(let i = 0; i < promises.length;i++){
           Promise.resolve(promises[i]).then((value)=>{
             processData(i,value);
           },reject)
        }
    })
}
// race 以第一个为准，第一个成功那就是成功 第一个失败那就是失败，可以用来竞速
Promise.race = function(promises){
    return new Promise((resolve,reject)=>{
        for(let i = 0; i < promises.length;i++){
           Promise.resolve(promises[i]).then(resolve,reject)
        }
    })
}






/*
// .then中返回promise并且resolve中的值也是一个异步promise
const promise = new Promise((resolve,reject)=>{
    resolve('ok');
})
let promise2 = promise.then(data=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve的值也是一个异步promise
            resolve(new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    resolve('123213213')
                },1000)
            }))
        },1000)
    })
})

promise2.then((data)=>{
    // 两秒后打印 success 123213213
    console.log('success',data)
},(err)=>{
    console.log('fail',err);
})
*/


// 当Promise.resolve中是一个promise，要在resolve中递归判断value.then()
Promise.resolve(new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve(new Promise((resolve,reject) => {
            setTimeout(() => {
                resolve(100)
            },1000)
          }))
    },1000)
})).then( res => {
    console.log(res,'res');
})



// Promise.all([readFile(path.resolve(__dirname,'name.txt'),'utf8'),readFile(path.resolve(__dirname,'age.txt'),'utf8'),13]).then(data=>{
//     console.log(data);
// }).catch((err)=>{
//     console.log(err);
// });



// A+规范检验 给自己的promise增加这个方法
Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd
}
// npm install promises-aplus-tests -g 全局安装只能在命令行中使用
// promises-aplus-tests promise-3.js 在当前文件夹目录下执行 这条命令
module.exports = Promise;